package com.example.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.constant.ExecuteCodeStatusEnum;
import com.example.constant.JudgeInfoEnum;
import com.example.dao.ProblemSubmitMapper;
import com.example.exception.BusinessException;
import com.example.pojo.judge.JudgeInfo;
import com.example.pojo.sandbox.ExecuteCodeRequest;
import com.example.pojo.sandbox.ExecuteCodeResponse;
import com.example.pojo.judge.JudgeCase;
import com.example.pojo.dto.problem.ProblemSubmitAddRequest;
import com.example.pojo.entity.question.Problem;
import com.example.pojo.entity.question.ProblemSubmit;
import com.example.constant.AppHttpCodeEnum;
import com.example.constant.LanguageEnum;
import com.example.pojo.sandbox.ExecuteMessage;
import com.example.service.ProblemService;
import com.example.service.ProblemSubmitService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProblemSubmitServiceImpl extends ServiceImpl<ProblemSubmitMapper, ProblemSubmit> implements ProblemSubmitService {

    @Autowired
    private ProblemSubmitMapper problemSubmitMapper;

    @Autowired
    private SandboxServiceImpl sandboxService;

    @Autowired
    private ProblemService problemService;

    // 题目提交运行
    @Override
    public JudgeInfo doProblemSubmit(ProblemSubmitAddRequest problemSubmitAddRequest) throws JsonProcessingException {
        // 校验编程语言是否合法
        String language = problemSubmitAddRequest.getLanguage();
        LanguageEnum languageEnum = LanguageEnum.getEnumByValue(language);
        if (languageEnum == null) {
            throw new BusinessException(AppHttpCodeEnum.LANGUAGE_NOT_SUPPORT);
        }
        // 判断提交的代码是否为空
        String code = problemSubmitAddRequest.getCode();
        if (code == null || code.isEmpty()) {
            throw new BusinessException(AppHttpCodeEnum.CODE_EMPTY);
        }
        // 判断提交的题目id是否有效
        Problem problem = problemService.getById(problemSubmitAddRequest.getProblemId());
        if (problem == null) {
            throw new BusinessException(AppHttpCodeEnum.PROBLEM_NOT_EXIST);
        }
        // 封装判题需要信息
        String judgeCase = problem.getJudgeCase();
        JudgeCase[] models = new ObjectMapper().readValue(judgeCase, JudgeCase[].class);
        List<String> inputList = Arrays.stream(models)
                .map(JudgeCase::getInput)
                .collect(Collectors.toList());
        ExecuteCodeRequest executeCodeRequest = new ExecuteCodeRequest(inputList, code, language);
        // 调用沙箱对代码编译执行并返回结果
        ExecuteCodeResponse executeCodeResponse = sandboxService.compileAndRunCode(executeCodeRequest);
        return judgeSubmitResult(executeCodeResponse, judgeCase);
    }

    // 根据运行信息进行判题
    private JudgeInfo judgeSubmitResult(ExecuteCodeResponse executeCodeResponse,String judgeCase) {
        // 初始化返回数据
        JudgeInfo judgeInfo = new JudgeInfo();
        // 根据编译运行后返回的状态码选择该如何进行处理
        // 运行正常
        if (executeCodeResponse.getStatus().equals(ExecuteCodeStatusEnum.SUCCESS.getValue())) {
            // 获取返回的运行信息列表
            List<ExecuteMessage> executeMessageList = executeCodeResponse.getExecuteMessageList();
            List<String> outputList = executeMessageList.stream().map(ExecuteMessage::getMessage).toList();
            // 获取期待的返回结果与输入数据
            List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCase, JudgeCase.class);
            List<String> expectOutputList = judgeCaseList.stream().map(JudgeCase::getOutput).toList();
            List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).toList();
            // 获取测试用例的个数
            int total = inputList.size();
            // 测试用例的通过个数
            int pass = 0;
            // 测试示例花费的最长时间
            Long maxTime = Long.MIN_VALUE;
            // 循环判断运行结果是否正确，对结果进行封装
            for (int i = 0; i < total; i++) {
                // 对花费的最长时间进行判断
                if (executeMessageList.get(i).getTime() > maxTime) {
                    maxTime = executeMessageList.get(i).getTime();
                }
                // 当有异常不符合预期的运行结果出现时
                if (!expectOutputList.get(i).equals(outputList.get(i))) {
                    judgeInfo.setInput(inputList.get(i));
                    judgeInfo.setOutput(outputList.get(i));
                    judgeInfo.setExpectedOutput(expectOutputList.get(i));
                    judgeInfo.setStatus(JudgeInfoEnum.WRONG_ANSWER.getValue());
                    judgeInfo.setMessage(JudgeInfoEnum.WRONG_ANSWER.getText());
                    break;
                } else {
                    pass++;
                }
            }
            judgeInfo.setPass(pass);
            judgeInfo.setTotal(total);
            judgeInfo.setTime(maxTime);
            if (pass == total) {
                judgeInfo.setStatus(JudgeInfoEnum.ACCEPTED.getValue());
                judgeInfo.setMessage(JudgeInfoEnum.ACCEPTED.getText());
            }
        } else if (executeCodeResponse.getStatus().equals(ExecuteCodeStatusEnum.RUN_FAILED.getValue())){
            // 运行失败
            judgeInfo.setStatus(JudgeInfoEnum.RUNTIME_ERROR.getValue());
            judgeInfo.setMessage(JudgeInfoEnum.RUNTIME_ERROR.getText());
        }
        // TODO 缺少对编译异常情况下的处理，需要完善
        return judgeInfo;
    }

}
